package cn.arrow.note.validation.controller;

import cn.arrow.note.validation.common.enums.ResultCodeEnum;
import cn.arrow.note.validation.common.exception.GlobalException;
import cn.arrow.note.validation.common.util.ValidationUtils;
import cn.arrow.note.validation.common.vo.ResultObject;
import cn.arrow.note.validation.entity.dto.UserDTO;
import cn.arrow.note.validation.specific.SpecificValue;
import cn.hutool.core.util.StrUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import javax.validation.constraints.NotBlank;

/**
 * 参数校验Controller
 *
 * @author zimo
 * @date 2021-11-28
 **/

@Validated
@RestController
@RequestMapping("/validate")
public class ValidationController {

    private Logger log = LoggerFactory.getLogger(ValidationController.class);

    /**
     * get、delete请求使用requestParam/PathVariable形式传递参数的，
     * 参数校验需要在Controller添加上@Validated注解，并在参数列表中添加对应的校验注解即可
     *
     * @param id ID
     * @return true/false 成功或失败
     */
    @GetMapping("/get")
    public ResultObject<Boolean> validateGetRequest(@NotBlank(message = "id不能为空") String id,
                                                    @NotBlank(message = "appkey不能为空") String appkey) {
        // 具体业务逻辑调用
        log.info("id [{}] appKey [{}]", id, appkey);
        return ResultObject.success();
    }

    /**
     * post、put等请求使用requestBody形式传递参数的，
     * 在参数列表中使用@Valid或者@Validated进行校验即可
     *
     * @param userDTO 入参
     * @return true/false 成功或失败
     */
    @PostMapping("/validatePostRequest")
    public ResultObject<Boolean> validatePostRequest(@Valid @RequestBody UserDTO userDTO) {
        // 具体业务逻辑调用
        log.info("userDTO [{}]", userDTO);
        return ResultObject.success();
    }

    /**
     * if...else参数校验
     *
     * @param userDTO 入参
     * @return true/false 成功或失败
     */
    @PostMapping("/validate")
    public ResultObject<Boolean> validate(@RequestBody UserDTO userDTO) {
        if (StrUtil.isBlank(userDTO.getUsername())) {
            throw new GlobalException(ResultCodeEnum.USER_PARAMETER_ERROR.getCode(), "用户名不能为空");
        }
        if (StrUtil.isBlank(userDTO.getPassword())) {
            throw new GlobalException(ResultCodeEnum.USER_PARAMETER_ERROR.getCode(), "密码不能为空");
        }
        if (StrUtil.isBlank(userDTO.getEmail())) {
            throw new GlobalException(ResultCodeEnum.USER_PARAMETER_ERROR.getCode(), "邮箱不能为空");
        }
        // 具体业务逻辑调用
        log.info("userDTO [{}]", userDTO);
        return ResultObject.success();
    }

    /**
     * 【分组校验】@Validated注解实现
     *
     * @param userDTO 入参
     * @return true/false 成功或失败
     */
    @PostMapping("/validateGroupOne")
    public ResultObject<Boolean> validateGroupOne(@Validated(value = {UserDTO.Update.class}) @RequestBody UserDTO userDTO) {
        // 具体业务逻辑调用
        log.info("userDTO [{}]", userDTO);
        return ResultObject.success();
    }


    /**
     * 【分组校验】自定义工具类实现
     *
     * @param userDTO 入参
     * @return true/false 成功或失败
     */
    @PostMapping("/validateGroup")
    public ResultObject<Boolean> validateGroup(@RequestBody UserDTO userDTO) {
        // 更新校验
        ValidationUtils.validateObject(userDTO, UserDTO.Update.class);
        // 具体业务逻辑调用
        log.info("userDTO [{}]", userDTO);
        return ResultObject.success();
    }

    /**
     * 【嵌套校验】
     *
     * @param userDTO 入参
     * @return true/false 成功或失败
     */
    @PostMapping("/validateInclude")
    public ResultObject<Boolean> validateInclude(@Valid @RequestBody UserDTO userDTO) {
        // 更新校验
        ValidationUtils.validateObject(userDTO, UserDTO.Update.class);
        // 具体业务逻辑调用
        log.info("userDTO [{}]", userDTO);
        return ResultObject.success();
    }

    @PostMapping("/specific")
    public ResultObject<Boolean> validateInclude(@SpecificValue(strValues = {"AA", "BB"}) String stringValue,
                                                 @SpecificValue(intValues = {1, 2}) Integer intValue) {
        // 具体业务逻辑调用
        log.info("stringValue [{}] intValue [{}]", stringValue, intValue);
        return ResultObject.success();
    }


}
